#pragma once

#include <string>
#include <filesystem>
#include <memory>
#include <glm/glm.hpp>

enum class ELightingModel
{
	None,
	DiffuseShininess,
	Diffuse,
};

class FShaderProgram
{
public:

	explicit FShaderProgram(const uint32_t InProgramHandle);

	~FShaderProgram();

	void Use() const;

	void SetBool(const std::string& Name, const bool Value) const;

	void SetInt(const std::string& Name, const int Value) const;

	void SetFloat(const std::string& Name, const float Value) const;

	void SetMat4(const std::string& Name, const glm::mat4& Mat) const;
	void SetVec3(const std::string& Name, const glm::vec3& Vec3) const;

	ELightingModel GetLightingModel()const
	{
		return LightingModel;
	}

	void SetLightingModel(ELightingModel InLightingModel)
	{
		LightingModel = InLightingModel;
	}

private:
	ELightingModel LightingModel = ELightingModel::DiffuseShininess;
	uint32_t ProgramHandle = 0;
};

inline void PrintSharderLog(const uint32_t Handle, const std::string& InfoStr);

inline void PrintProgramLog(const uint32_t Handle, const std::string& InfoStr);

class ShaderBuild
{
public:
	using Path = std::filesystem::path;

	ShaderBuild& SetVertexShaderFileName(const Path& FileName)
	{
		VertexFileName = FileName;
		return *this;
	}

	ShaderBuild& SetFragmentShaderFileName(const Path& FileName)
	{
		FragmentFileName = FileName;
		return *this;
	}

	enum class EShaderType { Vertex, Fragment };

	std::optional<uint32_t> CompileShaderFromSrcCode(const EShaderType Type, const char* CodeStr) const;

	[[nodiscard]] std::optional<uint32_t> CompileShader(const std::string& FileName, const EShaderType Type) const;


	[[nodiscard]] std::shared_ptr<FShaderProgram> Link(const std::optional<uint32_t> VertexHandle, const std::optional<uint32_t> FragmentHandle) const;

	[[nodiscard]] std::shared_ptr<FShaderProgram> Build() const;

	[[nodiscard]] std::shared_ptr<FShaderProgram> BuildWithSrcCode(const std::string& VSCode, const std::string& FSCode);

private:
	Path VertexFileName;
	Path FragmentFileName;
};
